package com.iflyings.android.dataconfig

import android.content.Context
import android.os.SystemClock
import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4

import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*
import kotlin.random.Random

/**
 * Instrumented test, which will execute on an Android device.
 *
 * See [testing documentation](http://d.android.com/tools/testing).
 */
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
    enum class Type {
        Type_0, Type_1, Type_2, Type_3, Type_4, Type_5;

        companion object {
            fun random(): Type {
                val i = Random.nextInt(values().size)
                return values()[i]
            }
        }
    }

    class Clazz(private val value: String) {
        override fun toString(): String {
            return value
        }

        override fun equals(other: Any?): Boolean {
            if (other == null || other !is Clazz) {
                return false
            }
            return value == other.value
        }

        override fun hashCode(): Int {
            return value.hashCode()
        }

        companion object {
            fun random(): Clazz {
                return Clazz(SystemClock.uptimeMillis().toString())
            }
        }
    }

    init {
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
        dbCreate(appContext.cacheDir.absolutePath + "/config.ini")
        Log.i("test", "dbPath: ${appContext.cacheDir.absolutePath + "/config.ini"}")
    }

    @Test
    fun useAppContext() {
        // Context of the app under test.
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
        assert(appContext.packageName.startsWith("com.iflyings.android.dataconfig"))
    }

    @Test
    fun testLocalData() {
        var lParamInt by dbLoader<Int>(0)
        var lParamBoolean by dbLoader(false)
        var lParamLong by dbLoader(0L)
        var lParamFloat by dbLoader(0f)
        var lParamDouble by dbLoader(0.0)
        var lParamString by dbLoader("")
        var lParamEnum by dbLoader(Type.Type_0)
        var lParamClass by dbLoader(Clazz(""))

        for (i in 0 until TEST_COUNT) {
            Random.nextInt().also {
                lParamInt = it
                assertEquals(it, lParamInt)
            }
            Random.nextBoolean().also {
                lParamBoolean = it
                assertEquals(it, lParamBoolean)
            }
            Random.nextLong().also {
                lParamLong = it
                assertEquals(it, lParamLong)
            }
            Random.nextFloat().also {
                lParamFloat = it
                assertEquals(it, lParamFloat)
            }
            Random.nextDouble().also {
                lParamDouble = it
                assertEquals(it, lParamDouble, 0.00001)
            }
            SystemClock.uptimeMillis().toString().also {
                lParamString = it
                assertEquals(it, lParamString)
            }
            Type.random().also {
                lParamEnum = it
                assertEquals(it, lParamEnum)
            }
            Clazz.random().also {
                lParamClass = it
                assertEquals(it, lParamClass)
            }
        }
    }

    var Context.rParamInt by dbRLoader<Int>(0)
    var Context.rParamBoolean by dbRLoader(false)
    var Context.rParamLong by dbRLoader(0L)
    var Context.rParamFloat by dbRLoader(0f)
    var Context.rParamDouble by dbRLoader(0.0)
    var Context.rParamString by dbRLoader("")
    var Context.rParamEnum by dbRLoader(Type.Type_0)
    var Context.rParamClass by dbRLoader(Clazz(""))
    @Test
    fun testRemoteData() {
        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
        for (i in 0 until TEST_COUNT) {
            Random.nextInt().also {
                appContext.rParamInt = it
                assertEquals(it, appContext.rParamInt)
            }
            Random.nextBoolean().also {
                appContext.rParamBoolean = it
                assertEquals(it, appContext.rParamBoolean)
            }
            Random.nextLong().also {
                appContext.rParamLong = it
                assertEquals(it, appContext.rParamLong)
            }
            Random.nextFloat().also {
                appContext.rParamFloat = it
                assertEquals(it, appContext.rParamFloat)
            }
            Random.nextDouble().also {
                appContext.rParamDouble = it
                assertEquals(it, appContext.rParamDouble, 0.00001)
            }
            SystemClock.uptimeMillis().toString().also {
                appContext.rParamString = it
                assertEquals(it, appContext.rParamString)
            }
            Type.random().also {
                appContext.rParamEnum = it
                assertEquals(it, appContext.rParamEnum)
            }
            Clazz.random().also {
                appContext.rParamClass = it
                assertEquals(it, appContext.rParamClass)
            }
        }
    }

    companion object {
        private const val TEST_COUNT = 10
    }
}